package com.xiake.dao.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;

import com.xiake.core.spring.SpringContextHolder;
import com.xiake.utils.MyBatisDaoUtils;

/**
 * @author qilong
 * @version 创建时间：2014年9月20日 下午8:28:17 类说明： Mybatis Dao父类：用于自定义SQL Dao的实现
 * @param <T>
 *            实体类泛型
 * @param <PK>
 *            主键类型
 */
@SuppressWarnings("unchecked")
public class MybatisBaseDao<T, PK extends Serializable> implements
		BaseDao<T, PK> {
	/**
	 * Log variable for all child classes. Uses LogFactory.getLog(getClass())
	 * from Commons Logging
	 */
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	private Class<T> persistentClass;

	public MybatisBaseDao(final Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	public final SqlSessionTemplate getSqlSessionTemplate() {
		SqlSessionTemplate sessiontemplate = SpringContextHolder
				.getBean("sessiontemplate");
		return sessiontemplate;
	}

	@Override
	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	/****************** 返回list记录查询 *************************/
	/**
	 * 查询所有列表，无条件参数 例如：select * from user
	 * 
	 * @return List<T>
	 * */
	@Override
	public List<T> getAll() throws Exception {
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getSelectQuery(ClassUtils
						.getShortName(this.persistentClass)), null);
	}

	/**
	 * 查询所有列表，并去除重复项
	 * 
	 * @return List<T>
	 */
	@Override
	public List<T> getAllDistinct() throws Exception {
		Collection<T> result = new LinkedHashSet<T>(getAll());
		return new ArrayList<T>(result);
	}

	/**
	 * 按照指定条件查询列表 例如：select * from user where xxxxx
	 * 
	 * @param 查询条件集合
	 * @return List<T>
	 * */
	@Override
	public List<T> query(Map<?, ?> conditions) throws Exception {
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getSelectQuery(ClassUtils
						.getShortName(this.persistentClass)), conditions);
	}

	/**
	 * 按照指定条件查询列表扩展方法 例如：select * from user where xxxxx
	 * 
	 * @param 查询条件集合
	 * @param 扩展方法后缀名
	 * @return List<T>
	 * */
	@Override
	public List<T> query(Map<?, ?> conditons, String specificName)
			throws Exception {
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getSelectQuery(ClassUtils
						.getShortName(this.persistentClass)) + specificName,
				conditons);
	}

	/**
	 * 按照指定条件分页查询
	 * 
	 * @param conditions
	 *            ：查询条件集合
	 * @return List<T>
	 * */
	@Override
	public List<T> page(Map<?, ?> conditions) throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getPageQuery(ClassUtils
						.getShortName(this.persistentClass)), conditions);
	}

	/**
	 * 根据指定条件分页查询扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：分页查询扩展方法后缀名
	 * @return List<T>
	 */
	@Override
	public List<T> page(Map<?, ?> conditions, String specificName)
			throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getPageQuery(ClassUtils
						.getShortName(this.persistentClass)) + specificName,
				conditions);
	}

	/**
	 * 按照指定条件分页查询
	 * 
	 * @param conditions
	 *            ：查询条件集合
	 * @return List<T>
	 * */
	@Override
	public List<T> pageList(Map<?, ?> conditions) throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getSelectQuery(ClassUtils
						.getShortName(this.persistentClass)), conditions);
	}

	/**
	 * 根据指定条件分页查询扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：分页查询扩展方法后缀名
	 * @return List<T>
	 */
	@Override
	public List<T> pageList(Map<?, ?> conditions, String specificName)
			throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (List<T>) getSqlSessionTemplate().selectList(
				MyBatisDaoUtils.getSelectQuery(ClassUtils
						.getShortName(this.persistentClass)) + specificName,
				conditions);
	}

	/********************************************************/
	/*********************** 统计数据 ***************************/
	/**
	 * 按照指定条件统计数据
	 * 
	 * @return int
	 * */
	@Override
	public int count(Map<?, ?> conditions) throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (Integer) getSqlSessionTemplate().selectOne(
				MyBatisDaoUtils.getCountsQuery(ClassUtils
						.getShortName(this.persistentClass)), conditions);

	}

	/**
	 * 根据指定条件统计数据扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：统计数据扩展方法后缀名
	 * @return int
	 */
	@Override
	public int count(Map<?, ?> conditions, String specificName)
			throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (Integer) getSqlSessionTemplate().selectOne(
				MyBatisDaoUtils.getCountsQuery(ClassUtils
						.getShortName(this.persistentClass)) + specificName,
				conditions);
	}

	@Override
	public int countList(Map<?, ?> conditions) throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (Integer) getSqlSessionTemplate().selectOne(
				MyBatisDaoUtils.getCountListQuery(ClassUtils
						.getShortName(this.persistentClass)), conditions);

	}

	/**
	 * 根据指定条件统计数据扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：统计数据扩展方法后缀名
	 * @return int
	 */
	@Override
	public int countList(Map<?, ?> conditions, String specificName)
			throws Exception {
		if (conditions == null)
			conditions = MapUtils.EMPTY_MAP;
		return (Integer) getSqlSessionTemplate().selectOne(
				MyBatisDaoUtils.getCountListQuery(ClassUtils
						.getShortName(this.persistentClass)) + specificName,
				conditions);
	}

	/********************************************************/
	/****************** 返回一条记录查询 *************************/

	/**
	 * 根据指定条件查询记录扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：查询记录方法后缀名
	 * @return T
	 */
	@Override
	public T get(Map<?, ?> conditions, String specificName) throws Exception {
		String statement = MyBatisDaoUtils.getFindQuery(ClassUtils
				.getShortName(this.persistentClass)) + specificName;
		T object = (T) getSqlSessionTemplate().selectOne(statement, conditions);
		return object;
	}

	/**
	 * 根据主键获取对象
	 * 
	 * @param id
	 *            主键
	 * @return 返回当前对象
	 * */
	@Override
	public T get(PK id) throws Exception {
		String statement = MyBatisDaoUtils.getFindQueryByPK(ClassUtils
				.getShortName(this.persistentClass));
		T object = (T) getSqlSessionTemplate().selectOne(statement, id);
		// if (object == null) {
		// logger.warn("Uh oh, '" + this.persistentClass + "' object with id '"
		// + id +
		// "' not found...");
		// throw new Exception(ClassUtils.getShortName(this.persistentClass));
		// }
		return object;
	}

	/**
	 * 根据指定条件查询记录
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @return T
	 */
	@Override
	public T get(Map<?, ?> conditions) throws Exception {
		String statement = MyBatisDaoUtils.getFindQuery(ClassUtils
				.getShortName(this.persistentClass));
		T object = (T) getSqlSessionTemplate().selectOne(statement, conditions);
		return object;
	}

	/********************************************************/

	/************************* 保存方法 *******************************/
	/**
	 * 保存数据操作，根据ID是否为空来判断是添加操作，还是修改操作 0-失败 1-成功
	 * 
	 * @param object
	 * @return T
	 */
	@Override
	public Integer save(final T object) throws Exception {
		Integer result = 0;
		String className = ClassUtils.getShortName(object.getClass());
		Object primaryKey = MyBatisDaoUtils.getPrimaryKeyValue(object);
		String keyId = null;
		if (primaryKey != null) {
			keyId = primaryKey.toString();
		}
		if (StringUtils.isBlank(keyId)) {
			// 如果ID为空 是添加操作
			result = getSqlSessionTemplate().insert(
					MyBatisDaoUtils.getInsertQuery(className), object);
		} else {
			// 如果ID不为空 是修改操作
			MyBatisDaoUtils.prepareObjectForSaveOrUpdate(object);
			result = getSqlSessionTemplate().update(
					MyBatisDaoUtils.getUpdateQuery(className), object);
		}
		return result;
	}

	/**
	 * 保存数据操作扩展方法，根据ID是否为空来判断是添加操作，还是修改操作
	 * 
	 * @param object
	 * @param specificName
	 *            :扩展方法后缀名
	 * @return T
	 */
	@Override
	public Integer save(T object, String specificName) throws Exception {
		Integer result = 0;
		String className = ClassUtils.getShortName(object.getClass());
		Object primaryKey = MyBatisDaoUtils.getPrimaryKeyValue(object);
		String keyId = null;
		if (primaryKey != null) {
			keyId = primaryKey.toString();
		}
		if (StringUtils.isBlank(keyId)) {
			// 如果ID为空 是添加操作
			result = getSqlSessionTemplate().insert(
					MyBatisDaoUtils.getInsertQuery(className) + specificName,
					object);
		} else {
			// 如果ID不为空 是修改操作
			MyBatisDaoUtils.prepareObjectForSaveOrUpdate(object);
			result = getSqlSessionTemplate().update(
					MyBatisDaoUtils.getUpdateQuery(className) + specificName,
					object);
		}
		return result;
	}

	// @Override
	// public T save(final T object,Boolean ADD)throws Exception {
	// String className = ClassUtils.getShortName(object.getClass());
	// if (ADD) {
	// int
	// rows=getSqlSessionTemplate().insert(MyBatisDaoUtils.getInsertQuery(className),
	// object);
	// if(rows==0){
	// throw new Exception("保存数据失败！");
	// }
	// } else {
	// //MyBatisDaoUtils.prepareObjectForSaveOrUpdate(object);
	// int
	// rows=getSqlSessionTemplate().update(MyBatisDaoUtils.getUpdateQuery(className),
	// object);
	// if(rows==0){
	// throw new Exception("修改数据失败！");
	// }
	// }
	// if (MyBatisDaoUtils.getPrimaryKeyValue(object) == null) {
	// throw new ObjectRetrievalFailureException(className, object);
	// } else {
	// return object;
	// }
	// }
	/**************************************************************/
	/*************************** 删除方法 *****************************/
	/**
	 * 根据指定条件删除数据
	 * 
	 * @param conditions
	 *            ：条件集合
	 */
	@Override
	public void remove(Map<String, Object> conditions) throws Exception {
		try {
			getSqlSessionTemplate().delete(
					MyBatisDaoUtils.getDeleteQuery(ClassUtils
							.getShortName(this.persistentClass)), conditions);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 根据指定条件删除数据扩展方法
	 * 
	 * @param conditions
	 *            ：条件集合
	 * @param specificName
	 *            ：删除方法后缀名
	 */
	@Override
	public void remove(Map<String, Object> conditions, String specificName)
			throws Exception {
		try {
			getSqlSessionTemplate()
					.delete(MyBatisDaoUtils.getDeleteQuery(ClassUtils
							.getShortName(this.persistentClass)) + specificName,
							conditions);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/***************************************************************/

}
